<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name=viewport content=width=device-width,initial-scale=1>
  <title>TodoMVC with Hyphen</title>
  <script src="../-.js"></script>
  <script>
    // TodoMVC in Hyphen. November 23 - 24, 2023

    // singleton global store
    const todoStore = globalThis._$store = new class TodoStore extends Store {
      constructor() {
        super({ todos: [], filter: 'all' });
      }

      addTodo(text) {
        const newTodos = [...this.state.todos, { text, completed: false }];
        this.setState({ todos: newTodos });
      }

      deleteTodo(index) {
        const newTodos = this.state.todos.filter((_, i) => i !== index);
        this.setState({ todos: newTodos });
      }

      toggleComplete(index) {
        const newTodos = this.state.todos.map((todo, i) => {
          if (i === index) {
            return { ...todo, completed: !todo.completed };
          }
          return todo;
        });
        this.setState({ todos: newTodos });
      }

      filterTodos(filter) {
        this.setState({ filter });
      }

      clearCompleted() {
        const newTodos = this.state.todos.filter(todo => !todo.completed);
        this.setState({ todos: newTodos });
      }

      getFilteredTodos() {
        return this.state.todos.filter(todo => {
          if (this.state.filter === 'active') return !todo.completed;
          if (this.state.filter === 'completed') return todo.completed;
          return true;
        });
      }
    }

    class TodoItem extends $ {
      static get attrs() {
        return ['text', 'completed', 'index'];
      }

      constructor() {
        super({ editing: false, completed: false });
      }

      connectedCallback() {
        super.connectedCallback();
        this.state.completed = this.completed;
      }

      toggleComplete() {
        todoStore.toggleComplete(parseInt(this.index));
      }

      startEditing() {
        this.state.editing = true;
        return true;
      }

      finishOnEnter(keyup) {
        if (keyup.key == 'Enter') {
          this.finishEditing();
        }
      }

      finishEditing() {
        this.state.editing = false;
        this.text = this.shadow.querySelector('#editor').value;
        todoStore.state.todos[this.index].text = this.text;
        todoStore.sync();
      }

      delete() {
        todoStore.deleteTodo(parseInt(this.index));
      }

      styles() {
        return `
          :host {
            display: block;
            margin-bottom: 10px;
          }
          li {
            background-color: white;
            border-radius: 5px;
            padding: 10px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
            transition: background-color 0.3s ease;
            display: flex;
            gap: 10px;
            align-items: center;
          }
          li.completed {
            background-color: #e6e6e6;
          }
          li.completed span {
            text-decoration: line-through;
            color: #393939;
          }
          li.editing {
            background-color: #fdfdff;
          }
          input[type="checkbox"] {
            margin-right: 10px;
          }
          input[type="text"] {
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 5px;
            width: 100%;
            box-sizing: border-box;
            display: none;
          }
          li.editing input[type="text"] {
            display: block;
          }
          li:not(.editing) span {
            display: inline-block;
          }
          li.editing span {
            display: none;
          }
          div.display {
            flex-grow: 1;
          }
          button {
            padding: 6px 10px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            background-color: #007bff;
            color: white;
          }
          button:hover {
            background-color: #0056b3;
          }
        `;
      }

      template() {
        const checkedClass = completed ? 'completed' : '';
        const editingClass = editing ? 'editing' : '';
        return `
          <li class="${checkedClass} ${editingClass}">
            <div class=display ondblclick="startEditing">
              <input type="checkbox" ${completed ? 'checked' : ''} onclick="toggleComplete">
              <span>${this.text}</span>
            </div>
            <input ${editing ? '' : 'readonly'} id=editor type="text" value="${this.text}" onblur="finishEditing" onkeyup="finishOnEnter">
            <button onclick="delete">Delete</button>
          </li>
        `;
      }
    }

    class TodoList extends $ {
      constructor() {
        super({ todos: [], filter: 'all' });
      }

      beforeUpdate() {
        this.state.todos = todoStore.getFilteredTodos();
        this.state.filter = todoStore.filter;
      }

      addOnEnter(keyup) {
        if ( keyup.key == 'Enter' ) {
          this.addTodo();
        }
      }

      addTodo() {
        const text = this.shadow.querySelector('#new-todo').value;
        if (text.trim()) {
          todoStore.addTodo(text.trim());
          this.shadow.querySelector('#new-todo').value = '';
        }
      }

      filterCompleted() {
        todoStore.filterTodos('completed');
      }

      filterActive() {
        todoStore.filterTodos('active');
      }

      filterAll() {
        todoStore.filterTodos('all');
      }

      clearCompleted() {
        todoStore.clearCompleted();
      }

      styles() {
        return `
          :host {
            display: flex;
            flex-direction: column;
          }
          main {
            display: flex;
          }
          ul {
            list-style-type: none;
            padding: 0;
          }
          input[type="text"] {
            padding: 10px;
            border: 2px solid dodgerblue;
            border-radius: 5px;
            flex-grow: 1;
            margin-right: 10px;
          }
          button {
            background-color: dodgerblue;
            color: white;
            border: none;
            padding: 10px 15px;
            border-radius: 5px;
            cursor: pointer;
          }
          button:hover {
            background-color: aquamarine;
          }
          .cent {
            text-align: center;
          }
        `;
      }

      template() {
        return `
          <main>
            <input autofocus type="text" id="new-todo" placeholder="Add a new task" onkeyup=addOnEnter>
            <button onclick="addTodo">Add</button>
          </main>
          <ul>
            ${this.state.todos.map((todo, index) => `
              <todo-item text="${todo.text}" completed="${todo.completed}" index="${index}"></todo-item>
            `).join('')}
          </ul>
          <div class=cent>
            <button onclick="filterAll">All</button>
            <button onclick="filterActive">Active</button>
            <button onclick="filterCompleted">Completed</button>
            <button onclick="clearCompleted">Clear Completed</button>
          </div>
        `;
      }
    }
  </script>
  <style>
    :root {
      font-family: system-ui, sans-serif;
    }
    body { background: powderblue; }
    footer {
      padding: 0.25rem 1.5rem;
      margin: 2rem 0.5rem 0.5rem 0.5rem;
      border: medium solid skyblue;
      border-radius: 0.5rem;
      color: darkgray;
      text-align: center;
      font-size: smaller;
    }

    footer a {
      color: inherit;
    }

    footer [cite] {
      font-size: x-small;
    }
  </style>
</head>
<body>
  <todo-list></todo-list>
  <footer>
    <span cite=https://openai.com>Created (mostly) in ChatGPT</span>
    <br>
    <a href=https://sharegpt.com/c/0PMQgMa>View the Chat</a>
    <a href=https://github.com/00000o1/->Get the Code</a>
  </footer>
</body>
</html>

